FOLIUM es una biblioteca de visualización de Python que se desarrolló con el único fin de visualizar datos geoespaciales. Es una biblioteca completamente gratuita.
Tabla de Contenido
- Acerca de los conjuntos de datos (DataFrame)
- Mapa Puntual
- Mapa de calor
- Mapa de calor con función tiempo
- Tareas a realizar
Base de datos: https://datos.madrid.es/portal/site/egob
Documentación: https://python-visualization.github.io/folium/
Alumnos:
Sento Marcos IbarraEstudio de la accidentalidad de la ciudad de Madrid mediante mapa de calor y puntual.
Caso de estudio
Crear un mapa de calor y puntual de los accidentes originados por vehiculos y bicicletas en el año 2022CREACION BASE DE DATOS ESTUDIO
In [7]:
# Librerias necesarias
import openpyxl
import pandas as pd
import numpy as np
import folium
from folium import plugins
import webbrowser
from pyproj import Transformer
In [8]:
# Creamos la Base de datos
base_datos= pd.read_excel('2022_Accidentalidad.xlsx')
base_datos.head(5)
Out[8]:
| num_expediente | fecha | hora | localizacion | numero | cod_distrito | distrito | tipo_accidente | estado_meteorológico | tipo_vehiculo | tipo_persona | rango_edad | sexo | cod_lesividad | lesividad | coordenada_x_utm | coordenada_y_utm | positiva_alcohol | positiva_droga | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2022S000001 | 2022-01-01 | 01:30:00 | AVDA. ALBUFERA, 19 | 19 | 13 | PUENTE DE VALLECAS | Alcance | Despejado | Turismo | Conductor | De 30 a 34 años | Mujer | NaN | NaN | 443359.226 | 4472082.272 | N | NaN |
| 1 | 2022S000001 | 2022-01-01 | 01:30:00 | AVDA. ALBUFERA, 19 | 19 | 13 | PUENTE DE VALLECAS | Alcance | Despejado | Turismo | Conductor | De 45 a 49 años | Hombre | NaN | NaN | 443359.226 | 4472082.272 | N | NaN |
| 2 | 2022S000002 | 2022-01-01 | 00:30:00 | PLAZA. CANOVAS DEL CASTILLO / PASEO. PRADO | 2 | 3 | RETIRO | Colisión fronto-lateral | NaN | Motocicleta hasta 125cc | Conductor | De 30 a 34 años | Hombre | NaN | NaN | 441155.351 | 4474129.588 | S | NaN |
| 3 | 2022S000002 | 2022-01-01 | 00:30:00 | PLAZA. CANOVAS DEL CASTILLO / PASEO. PRADO | 2 | 3 | RETIRO | Colisión fronto-lateral | NaN | Motocicleta hasta 125cc | Pasajero | De 35 a 39 años | Mujer | NaN | NaN | 441155.351 | 4474129.588 | N | NaN |
| 4 | 2022S000002 | 2022-01-01 | 00:30:00 | PLAZA. CANOVAS DEL CASTILLO / PASEO. PRADO | 2 | 3 | RETIRO | Colisión fronto-lateral | NaN | Turismo | Conductor | De 40 a 44 años | Hombre | NaN | NaN | 441155.351 | 4474129.588 | N | NaN |
Preparación Base de datos¶
In [11]:
print(base_datos.dtypes) # imprime el tipo de campo
print("Numero de registros =" , len( base_datos)) # imprime el tamaño de la base de datos
num_expediente object fecha datetime64[ns] hora object localizacion object numero object cod_distrito int64 distrito object tipo_accidente object estado_meteorológico object tipo_vehiculo object tipo_persona object rango_edad object sexo object cod_lesividad float64 lesividad object coordenada_x_utm float64 coordenada_y_utm float64 positiva_alcohol object positiva_droga float64 dtype: object Numero de registros = 47053
In [12]:
# Elimina los registros en blanco en los campos de coordenadas
accidentes_df = base_datos.dropna(subset=['coordenada_x_utm', 'coordenada_y_utm'])
Transformación de coordenadas¶
La geolocalización en el fichero de accidentes del ayuntamiento de Madrid se realiza con coordenadas UTM ETRS89 en el Huso 30. Para representar coordenadas en FOLIUM se necesitan coordenadas geográficas ETRS89
In [15]:
# Establecer los sistemas de transformación epsg:xxxx de entrada y epsg:yyyyy de salida
transformacion = Transformer.from_crs('epsg:25830','epsg:4258',always_xy=True)
puntos = list(zip(accidentes_df.coordenada_x_utm,accidentes_df.coordenada_y_utm)) # Crea una lista con todos los puntos
# Se recomienda trabajar con una copia independiente
accidentes_df = accidentes_df.copy()
coorgeo = np.array(list(transformacion.itransform(puntos)))
accidentes_df.loc[:,'longitud'] = coorgeo[:,0]
accidentes_df.loc[:,'latitud'] = coorgeo[:,1]
accidentes_df.head()
Out[15]:
| num_expediente | fecha | hora | localizacion | numero | cod_distrito | distrito | tipo_accidente | estado_meteorológico | tipo_vehiculo | ... | rango_edad | sexo | cod_lesividad | lesividad | coordenada_x_utm | coordenada_y_utm | positiva_alcohol | positiva_droga | longitud | latitud | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2022S000001 | 2022-01-01 | 01:30:00 | AVDA. ALBUFERA, 19 | 19 | 13 | PUENTE DE VALLECAS | Alcance | Despejado | Turismo | ... | De 30 a 34 años | Mujer | NaN | NaN | 443359.226 | 4472082.272 | N | NaN | -3.667437 | 40.39742 |
| 1 | 2022S000001 | 2022-01-01 | 01:30:00 | AVDA. ALBUFERA, 19 | 19 | 13 | PUENTE DE VALLECAS | Alcance | Despejado | Turismo | ... | De 45 a 49 años | Hombre | NaN | NaN | 443359.226 | 4472082.272 | N | NaN | -3.667437 | 40.39742 |
| 2 | 2022S000002 | 2022-01-01 | 00:30:00 | PLAZA. CANOVAS DEL CASTILLO / PASEO. PRADO | 2 | 3 | RETIRO | Colisión fronto-lateral | NaN | Motocicleta hasta 125cc | ... | De 30 a 34 años | Hombre | NaN | NaN | 441155.351 | 4474129.588 | S | NaN | -3.693594 | 40.41571 |
| 3 | 2022S000002 | 2022-01-01 | 00:30:00 | PLAZA. CANOVAS DEL CASTILLO / PASEO. PRADO | 2 | 3 | RETIRO | Colisión fronto-lateral | NaN | Motocicleta hasta 125cc | ... | De 35 a 39 años | Mujer | NaN | NaN | 441155.351 | 4474129.588 | N | NaN | -3.693594 | 40.41571 |
| 4 | 2022S000002 | 2022-01-01 | 00:30:00 | PLAZA. CANOVAS DEL CASTILLO / PASEO. PRADO | 2 | 3 | RETIRO | Colisión fronto-lateral | NaN | Turismo | ... | De 40 a 44 años | Hombre | NaN | NaN | 441155.351 | 4474129.588 | N | NaN | -3.693594 | 40.41571 |
5 rows × 21 columns
Selección de registros base de datos¶
In [17]:
print(accidentes_df["tipo_persona"].unique())
['Conductor' 'Pasajero' 'Peatón']
In [18]:
# Crear una nueva Dataframe que cumple las condiciones establecidas
acci_conductor = accidentes_df.loc[(accidentes_df['tipo_persona']=='Conductor')]
# si quisieramos introduccir más condicionantes --- & (accidentes_df['tipo_vehiculo']=='Turismo')& (accidentes_df['rango_edad']=='De 18 a 20 años')]
Mapa Puntual (MarkerCluster)
Los mapas puntuales permiten plasmar variables georeferenciadas, para un mejor entendimiento por parte del usuario de la distribucción de los mismas.
Diferentes plugins de Folium: https://python-visualization.github.io/folium/plugins.html
Iconos con prefijo 'fa': https://fontawesome.com/v5.15/icons?d=gallery&p=2&m=free
In [20]:
print(accidentes_df["tipo_vehiculo"].unique())
['Turismo' 'Motocicleta hasta 125cc' 'Motocicleta > 125cc' 'Furgoneta' 'Camión rígido' 'Todo terreno' 'Bicicleta EPAC (pedaleo asistido)' 'VMU eléctrico' 'Maquinaria de obras' 'Ciclomotor' 'Autobús articulado' 'Vehículo articulado' nan 'Otros vehículos con motor' 'Autocaravana' 'Autobús' 'Tractocamión' 'Bicicleta' 'Cuadriciclo ligero' 'Sin especificar' 'Autobús articulado EMT' 'Autobus EMT' 'Cuadriciclo no ligero' 'Camión de bomberos' 'Ambulancia SAMUR' 'Ciclo' 'Moto de tres ruedas > 125cc' 'Ciclomotor de dos ruedas L1e-B' 'Moto de tres ruedas hasta 125cc' 'Semiremolque' 'Patinete no eléctrico' 'Remolque' 'Otros vehículos sin motor']
In [21]:
# Crear el mapa base donde representar
mapa_accidentes = folium.Map(location=(40.43,-3.65), tiles = 'OpenStreetMap', zoom_start = 12)
# Crear diferentes dataframes, con tipo _persona= Conductor y Vehiculos= Turismo y Bicicleta
coche_df=acci_conductor.loc[(acci_conductor['tipo_vehiculo']=='Turismo')]
bici_df=acci_conductor.loc[(acci_conductor['tipo_vehiculo']=='Bicicleta')]
# crear un objeto de grupo de marcas para los incidentes en el DataFrame
coches = plugins.MarkerCluster( name="Accidentes_coche",).add_to(mapa_accidentes)
bicis = plugins.MarkerCluster( name="Accidentes_bicis",).add_to(mapa_accidentes)
# procesar el DataFrame y agregar cada punto de datos al grupo de marcas creado anteriormente
for lat, lng, label, in zip(coche_df.latitud, coche_df.longitud, coche_df['num_expediente']): #dos formas diferentes de llamar a un campo
folium.Marker(
location=[lat, lng],
icon=folium.Icon(color="orange", icon="car", prefix = 'fa'),
popup=label,
).add_to(coches)
for lat, lng, label, in zip(bici_df.latitud, bici_df.longitud, bici_df['num_expediente']): #dos formas diferentes de llamar a un campo
folium.Marker(
location=[lat, lng],
icon=folium.Icon(color="blue", icon="bicycle", prefix = 'fa'),
popup=label,
).add_to(bicis)
#Añadir controles
folium.LayerControl().add_to(mapa_accidentes)
draw = plugins.Draw(export=True)
draw.add_to(mapa_accidentes)
#Muestra mapa
#mapa_accidentes
# Salvar WebMapping
mapa_accidentes.save("madrid_accidentes.html")
webbrowser.open_new_tab('madrid_accidentes.html')
Out[21]:
True
Ubicación de contenedores vidrio y envases en Madrid. Mapa puntual.
In [23]:
'''
La base de datos es Contenedores_varios.csv, utilizamos ahora un fichero CSV
Es opcional colocar el tipo de separador y la codificación. Por defecto es , y UTF-8 peró hay ficheros csv
con formato sep=';', encoding = 'cp1252')
'''
contenedores_df = pd.read_csv('Contenedores_varios.csv', sep=';',low_memory = False)
contenedores_df.head()
Out[23]:
| Código Interno del Situad | Tipo Contenedor | Modelo | Descripcion Modelo | Cantidad | Lote | Distrito | Barrio | Tipo Vía | Nombre | Número | COORDENADA X | COORDENADA Y | LONGITUD | LATITUD | DIRECCION | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 168755 | ENVASES | NaN | Env 3200 CL | 1.0 | 1 | CENTRO | NaN | PLAZA | SALESAS | 9.0 | 441062.99 | 4475052.45 | -3.694768 | 40.424017 | PLAZA SALESAS. 9 |
| 1 | 168755 | VIDRIO | NaN | V 2200 CL VACRI | 1.0 | 1 | CENTRO | NaN | PLAZA | SALESAS | 9.0 | 441062.99 | 4475052.45 | -3.694768 | 40.424017 | PLAZA SALESAS. 9 |
| 2 | 168753 | VIDRIO | NaN | V 2200 CL | 1.0 | 1 | CENTRO | NaN | CALLE | MEJIA LEQUERICA | 20.0 | 440680.69 | 4475502.55 | -3.699317 | 40.428045 | CALLE MEJIA LEQUERICA. 20 |
| 3 | 170313 | RESTO | NaN | Res 800 | 1.0 | 1 | FUENCARRAL-EL PARDO | NaN | CALLE | ISLA DE JAVA | 55.0 | 441852.02 | 4482612.15 | -3.686160 | 40.492174 | CALLE ISLA DE JAVA. 55 |
| 4 | 169874 | ENVASES | NaN | Env 800 | 1.0 | 1 | FUENCARRAL-EL PARDO | NaN | AVENIDA | CARDENAL HERRERA ORIA | 271.0 | 438643.32 | 4481240.57 | -3.723888 | 40.479587 | AVENIDA CARDENAL HERRERA ORIA. 271 |
In [24]:
print(contenedores_df["Tipo Contenedor"].unique())
print(contenedores_df.dtypes) # imprime el tipo de campo
['ENVASES' 'VIDRIO' 'RESTO' 'ORGANICA' 'PAPEL-CARTON'] Código Interno del Situad object Tipo Contenedor object Modelo object Descripcion Modelo object Cantidad float64 Lote int64 Distrito object Barrio float64 Tipo Vía object Nombre object Número float64 COORDENADA X float64 COORDENADA Y float64 LONGITUD float64 LATITUD float64 DIRECCION object dtype: object
In [25]:
# Crear el mapa base donde representar
mapa_contenedores = folium.Map(location=(40.43,-3.65), tiles = 'OpenStreetMap', zoom_start = 12)
# Crear diferentes dataframes
vidrio_df=contenedores_df.loc[(contenedores_df['Tipo Contenedor']=='VIDRIO')]
envases_df=contenedores_df.loc[(contenedores_df['Tipo Contenedor']=='ENVASES')]
# crear un objeto de grupo de marcas para los incidentes en el DataFrame
vidrio = plugins.MarkerCluster( name="Contenedores Vidrio").add_to(mapa_contenedores)
envases = plugins.MarkerCluster( name = 'Contenedores envases').add_to(mapa_contenedores)
# procesar el DataFrame y agregar cada punto de datos al grupo de marcas creado anteriormente
for lat, lng, label in zip(vidrio_df.LATITUD, vidrio_df.LONGITUD, vidrio_df['Descripcion Modelo']):
folium.Marker(
location=[lat, lng],
icon=folium.Icon(color="green", icon="info-sign"),
popup=label,
).add_to(vidrio)
for lat, lng, label in zip(envases_df.LATITUD, envases_df.LONGITUD, envases_df['Descripcion Modelo']):
folium.Marker(
location=[lat, lng],
icon=folium.Icon(color="orange", icon="info-sign"),
popup=label,
).add_to(envases)
# Añadir control de mapas
folium.LayerControl().add_to(mapa_contenedores)
#Muestra mapa
mapa_contenedores
# Crear mapas
# mapa_contenedores.save("madrid_contenedores.html")
# webbrowser.open_new_tab('madrid_contenedores.html')
Out[25]:
Make this Notebook Trusted to load map: File -> Trust Notebook
